package org.flexthinker.binding.ui.form.binding.flex
{
    import flash.display.DisplayObject;

    import org.flexthinker.binding.ui.form.binding.BindingFieldFinder;
    import org.flexthinker.binding.ui.form.binding.MockForm;
    import org.hamcrest.assertThat;
    import org.hamcrest.core.not;
    import org.hamcrest.core.throws;
    import org.hamcrest.object.equalTo;
    import org.hamcrest.object.instanceOf;
    import org.hamcrest.object.notNullValue;

    import spark.components.Label;

    import spark.components.SkinnableContainer;

    public class DefaultBindingFieldFinderTest
    {
        private var form:MockForm;
        private var finder:BindingFieldFinder;
        private var listener:BindingFieldListenerCounter;

        public function DefaultBindingFieldFinderTest()
        {
        }

        [Before]
        public function setUp():void
        {
            form = new MockForm();
            finder = new DefaultBindingFieldFinder(form);
            listener = new BindingFieldListenerCounter();
        }

        [Test]
        public function testGetFields():void
        {
            form.label = new Label();
            var fields:Vector.<DisplayObject> = finder.getBindableFields();
            assertThat("initially form's fields are null as they're not intialized. Null fields shouldn't be returned as they're not bindable",
                            fields.length, not(equalTo(form.getBindableElements().length)));
            assertThat("only 1 field should be added because it's not null", fields.length, equalTo(1));
        }

        [Test]
        public function testThatFieldsAddedLaterAreCounted():void
        {
            var fields:Vector.<DisplayObject> = finder.getBindableFields();
            form.label = new Label();

            finder.addFinderListener( listener );
            finder.addFinderListener( listener );

            form.simulatePartAdded( "label", form.label );

            assertThat("listener should get called", listener.fieldAddedCounter, equalTo(1));
            assertThat("wrong field added", listener.fields["label"], equalTo(form.label));
            assertThat(finder.getBindableFields().length, equalTo(1));

            form.simulatePartRemoved("label", form.label);
            assertThat("listener should get called", listener.fieldRemovedCounter, equalTo(1));
            assertThat(finder.getBindableFields().length, equalTo(0));

            finder.removeAllListeners();
            form.simulatePartAdded( "label", form.label );
            assertThat("listener shouldn't get called", listener.fieldAddedCounter, equalTo(1));
            form.simulatePartRemoved("label", form.label);
            assertThat("listener shouldn't get called", listener.fieldRemovedCounter, equalTo(1));
        }

        [Test]
        public function testListenerIsAddedOnce():void
        {
            var fields:Vector.<DisplayObject> = finder.getBindableFields();
            form.label = new Label();

            finder.addFinderListener( listener );
            finder.addFinderListener( listener );

             form.simulatePartAdded( "label", form.label );

            assertThat("same listener shouldn't be added twice", listener.fieldAddedCounter, equalTo(1));
        }

        [Test]
        public function testReset():void
        {
            var fields:Vector.<DisplayObject> = finder.getBindableFields();
            form.label = new Label();

            finder.addFinderListener( listener );
            form.simulatePartAdded( "label", form.label );

            var prevFields:Vector.<DisplayObject> = finder.getBindableFields();
            finder.reset();

            form.simulatePartRemoved("label", form.label);
            form.label = null;

            assertThat("listener shouldn't get called after reset()", listener.fieldRemovedCounter, equalTo(0));
            assertThat( prevFields == finder.getBindableFields(), equalTo(false));
            assertThat( finder.getBindableFields().length, equalTo(0));

        }


        // negative tests

        [Test]
        public function testSetFormValidation():void
        {
            assertThat( function():void
            {
                finder.setForm(new SkinnableContainer());
            }, throws(instanceOf(Error)));

            assertThat( function():void
            {
                new DefaultBindingFieldFinder(null);
            }, throws(instanceOf(ArgumentError)));

        }


    }
}

import flash.utils.Dictionary;

import org.flexthinker.binding.ui.form.binding.BindingFieldFinderListener;
import org.hamcrest.AssertionError;

class BindingFieldListenerCounter implements BindingFieldFinderListener
{
    public var fields:Dictionary = new Dictionary(true);
    public var fieldAddedCounter:int = 0;
    public var fieldRemovedCounter:int = 0;

    public function BindingFieldListenerCounter():void
    {
    }

    public function fieldAdded(fieldName:String, instance:Object):void
    {
        fieldAddedCounter ++;
        if ( fields[fieldName] != null )
        {
            throw new AssertionError("Field already added");
        }
        fields[ fieldName ] = instance;
    }

    public function fieldRemoved(fieldName:String, instance:Object):void
    {
        fieldRemovedCounter++;
        if ( fields[fieldName] == null )
        {
            throw new AssertionError("Field doesn't exists");
        }
        fields[ fieldName ] = null;
    }
}
